/**
 * Copyright 2012 Brigham Young University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.byu.nlp.util;

import java.util.Arrays;

import com.google.common.base.Preconditions;

/**
 * @author rah67
 *
 */
public class Matrices {

	private Matrices() { }

	public static void addToSelf(double[][] mat, double beta) {
		for (int i = 0; i < mat.length; i++) {
			for (int j = 0; j < mat[i].length; j++) {
				mat[i][j] += beta;
			}
		}
	}

	public static double[][] clone(double[][] arr) {
		double[][] clone = new double[arr.length][];
		for (int i = 0; i < clone.length; i++) {
			clone[i] = arr[i].clone();
		}
		return clone;
	}

	/**
	 * Computes ret[i] = \sum_j mat[j][i]
	 */
	public static double[] sumOverFirst(double[][] mat) {
		Preconditions.checkNotNull(mat);
		if (mat.length == 0) {
			return new double[0];
		}
		
		double[] sum = new double[mat[0].length];
		for (int i = 0; i < mat.length; i++) {
			Preconditions.checkArgument(mat[i].length == sum.length, "matrix must be square");
			for (int j = 0; j < mat[i].length; j++) {
				sum[j] += mat[i][j];
			}
		}
		return sum;
	}

	/**
	 * Computes ret[i] = \sum_j mat[i][j]
	 */
	public static double[] sumOverSecond(double[][] mat) {
		Preconditions.checkNotNull(mat);
		
		double[] sum = new double[mat.length];
		for (int i = 0; i < sum.length; i++) {
			sum[i] = DoubleArrays.sum(mat[i]);
		}
		return sum;
	}

	public static void fill(double[][] matrix, double x) {
		for (double[] row : matrix) {
			Arrays.fill(row, x);
		}
	}

	public static void fill(double[][] matrix, double[] x) {
		Preconditions.checkArgument(matrix.length == x.length);
		for (int i = 0; i < matrix.length; i++) {
			Arrays.fill(matrix[i], x[i]);
		}
	}

	public static double sum(double[][] mat) {
		double sum = 0.0;
		for (int i = 0; i < mat.length; i++) {
			for (int j = 0; j < mat[i].length; j++) {
				sum += mat[i][j];
			}
		}
		return sum;
	}

	public static void divideToSelf(double[][] matrix, double x) {
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				matrix[i][j] /= x;
			}
		}
	}

	public static double[][] constant(double fill, int rows, int cols) {
		double[][] mat = new double[rows][];
		for (int r = 0; r < rows; r++) {
			mat[r] = DoubleArrays.constant(fill, cols);
		}
		return mat;
	}

	/**
	 * Copies the first matrix into the other.
	 */
	public static void copyInto(double[][] src, double[][] dest) {
		for (int i = 0; i < src.length; i++) {
			System.arraycopy(src[i], 0, dest[i], 0, src[i].length);
		}
	}

}
